package com.data.center.controller;

import com.data.center.dictionary.AdminDivisionRegion;
import com.data.center.dictionary.AdminDivisionStatus;
import com.data.center.entity.AdminDivision;
import com.data.center.exception.ResultBody;
import com.data.center.exception.exception.BizException;
import com.data.center.exception.info.CommonEnum;
import com.data.center.service.AdminDivisionService;
import com.data.center.util.AdminDivisionUtils;
import com.data.center.util.CalculateUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/AdminDivision")
@Slf4j
public class AdminDivisionController {

    @Autowired
    AdminDivisionService adminDivisionService;

    @Autowired
    AdminDivisionUtils adminDivisionUtils;

    // TODO: 提供一个根据 两列excel文件/任意形式能标识编码-名称关系的参数，进行全量区域编码更新的接口

    /*
    * 批量更新函数，仅支持输入6位区域编码链表进行全量更新
    * */
    public ResultBody fullUpdate(List<String> codeList, List<String> nameList) {

        codeList.forEach(item -> {
            if(!adminDivisionUtils.checkCodeLengthIsSix(item)) {
                throw new BizException(CommonEnum.CODE_SIZE_NOT_SIX);
            }
        });

        // 获取旧编码集
        List<CodeAndName> originalDataList = new ArrayList<>();
        adminDivisionService.listAllByStatus(Integer.parseInt(AdminDivisionStatus.IN_EFFECT.getKey())).forEach(
                item -> originalDataList.add(new CodeAndName(item.getCode(), item.getName()))
        );

        // 获取新编码集，自动将6位编码解析为8位编码
        List<CodeAndName> newDataList = new ArrayList<>();
        if (codeList.size() == nameList.size()) {
            for (int i = 0; i < codeList.size(); ++i) {
                newDataList.add(
                        new CodeAndName(adminDivisionUtils.getDivisionFatherCode(codeList.get(i)).substring(0, 2) + codeList.get(i), nameList.get(i)));
            }
        }

        CalculateUtils<CodeAndName> calculateUtils = new CalculateUtils<>();
        List<CodeAndName> intersection = calculateUtils.getIntersection(newDataList, originalDataList);

        log.info("交集" + intersection);

        // 插入新编码
        List<CodeAndName> newCodes = calculateUtils.firstMinusSecond(newDataList, intersection);
        log.info("newCodes" + newCodes.size() + newCodes);
        newCodes.forEach(item -> adminDivisionService.addNewOrUpdateWithEight(item.code, item.name, new Date()));

        // 删除失效编码
        List<CodeAndName> expiredCodes = calculateUtils.firstMinusSecond(originalDataList, intersection);
        Map usedCodes = new HashMap();
        String sixZero = "000000";
        usedCodes.put(AdminDivisionRegion.WEST.getKey() + sixZero, "");
        usedCodes.put(AdminDivisionRegion.HK_MO_TW.getKey() + sixZero, "");
        usedCodes.put(AdminDivisionRegion.EAST.getKey() + sixZero, "");
        usedCodes.put(AdminDivisionRegion.CENTRAL.getKey() + sixZero, "");
        usedCodes.put(AdminDivisionRegion.NORTHEAST.getKey() + sixZero, "");
        usedCodes.put(AdminDivisionRegion.DEFAULT.getKey() + sixZero, "");
        // 将大区编码、默认空编码从失效编码中删除，防止误删
        expiredCodes = expiredCodes.stream().filter(codeAndName -> usedCodes.get(codeAndName.code) != null).collect(Collectors.toList());

        log.info("expiredCodes" + expiredCodes.size() + expiredCodes);
        expiredCodes.forEach(item -> adminDivisionService.expireNow(item.code));

        return ResultBody.success();
    }

    /*
     * 批量更新函数，仅支持输入6位区域编码链表进行全量更新
     * 需要输入时间，
     * */
    public ResultBody fullUpdateWithTime(List<String> codeList, List<String> nameList, Date date) {

        codeList.forEach(item -> {
            if(!adminDivisionUtils.checkCodeLengthIsSix(item)) {
                throw new BizException(CommonEnum.CODE_SIZE_NOT_SIX);
            }
        });

        // 获取旧编码集
        List<CodeAndName> originalDataList = new ArrayList<>();
        adminDivisionService.listAllByStatus(Integer.parseInt(AdminDivisionStatus.IN_EFFECT.getKey())).forEach(
                item -> originalDataList.add(new CodeAndName(item.getCode(), item.getName()))
        );

        // 获取新编码集，自动将6位编码解析为8位编码
        List<CodeAndName> newDataList = new ArrayList<>();
        if (codeList.size() == nameList.size()) {
            for (int i = 0; i < codeList.size(); ++i) {
                newDataList.add(
                        new CodeAndName(adminDivisionUtils.getDivisionFatherCode(codeList.get(i)).substring(0, 2) + codeList.get(i), nameList.get(i).replace(" ", "")));
            }
        } else {
            throw new BizException("编码数量与名称数量不一致");
        }

        CalculateUtils<CodeAndName> calculateUtils = new CalculateUtils<>();
        List<CodeAndName> intersection = calculateUtils.getIntersection(newDataList, originalDataList);

        log.info("交集" + intersection);

        // 插入新编码
        List<CodeAndName> newCodes = calculateUtils.firstMinusSecond(newDataList, intersection);
        log.info("newCodes" + newCodes.size() + newCodes);
        newCodes.forEach(item -> adminDivisionService.addNewOrUpdateWithEight(item.code, item.name, date));

        // 删除失效编码
        List<CodeAndName> expiredCodes = calculateUtils.firstMinusSecond(originalDataList, intersection);
        Map usedCodes = new HashMap();
        String sixZero = "000000";
        usedCodes.put(AdminDivisionRegion.WEST.getKey() + sixZero, "");
        usedCodes.put(AdminDivisionRegion.HK_MO_TW.getKey() + sixZero, "");
        usedCodes.put(AdminDivisionRegion.EAST.getKey() + sixZero, "");
        usedCodes.put(AdminDivisionRegion.CENTRAL.getKey() + sixZero, "");
        usedCodes.put(AdminDivisionRegion.NORTHEAST.getKey() + sixZero, "");
        usedCodes.put(AdminDivisionRegion.DEFAULT.getKey() + sixZero, "");
        // 将大区编码、默认空编码从失效编码中删除，防止误删
        expiredCodes = expiredCodes.stream().filter(codeAndName -> usedCodes.get(codeAndName.code) != null).collect(Collectors.toList());
        log.info("expiredCodes" + expiredCodes.size() + expiredCodes);
        expiredCodes.forEach(item -> adminDivisionService.expire(item.code, date));

        return ResultBody.success();
    }


    private static class CodeAndName {
        public String code;
        public String name;

        public CodeAndName(String code, String name) {
            this.code = code;
            this.name = name;
        }

        @Override
        public String toString() {
            return "CodeAndName{" +
                    "code='" + code + '\'' +
                    ", name='" + name + '\'' +
                    '}';
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof CodeAndName)) return false;
            CodeAndName that = (CodeAndName) o;
            return Objects.equals(code, that.code) && Objects.equals(name, that.name);
        }

        @Override
        public int hashCode() {
            return Objects.hash(code, name);
        }
    }

    public static void main(String[] args) {
        List<CodeAndName> a = new ArrayList<>();
        a.add(new CodeAndName("1", "one"));
        a.add(new CodeAndName("2", "two"));

        List<CodeAndName> b = new ArrayList<>();
        b.add(new CodeAndName("1", "one"));

        CalculateUtils<CodeAndName> calculateUtils = new CalculateUtils<>();
        List<CodeAndName> intersection = calculateUtils.getIntersection(a, b);

        intersection.forEach(item -> System.out.println(item));

    }


    public ResultBody getEffectAdminDivisionByName(String name) {
        AdminDivision adminDivision = adminDivisionService.getByName(name);
        if (adminDivision == null) {
            List<AdminDivision> adminDivisions = adminDivisionService.searchByName(name);
            if (adminDivisions != null && adminDivisions.size() > 0) {
                throw new BizException(CommonEnum.ADMIN_DIVISION_NAME_CANT_GET);
            }
            throw new BizException(CommonEnum.ADMIN_DIVISION_NAME_NOT_EXIST);
        }
        return ResultBody.success(adminDivision);
    }

    public ResultBody searchByName(String name) {
        List<AdminDivision> adminDivisions = adminDivisionService.searchByName(name);
        if (adminDivisions != null && adminDivisions.size() > 0) {
            return ResultBody.success(adminDivisions);
        }
        throw new BizException(CommonEnum.ADMIN_DIVISION_NAME_NOT_EXIST);
    }

}
